package persistence.jdbc;

import interfaces.UserRepository;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import logger.ForumLogger;
import domain.users.Member;
import domain.users.User;

public class JDBCUserRepository implements UserRepository {

	/** sqlServer parameters */
	private Connection _sqlConnection;
	private String _driverName = "com.mysql.jdbc.Driver";


	public JDBCUserRepository() {
		JDBC_Config.SetConfig();
		try {
			Class.forName(_driverName).newInstance();

		} catch (InstantiationException e) {
			System.out.println(e.getMessage());
		} catch (IllegalAccessException e) {
			System.out.println(e.getMessage());
		} catch (ClassNotFoundException e) {
			System.out.println(e.getMessage());
		}
		try {
			_sqlConnection = DriverManager.getConnection(JDBC_Config.URL + JDBC_Config.DBNAME,
					JDBC_Config.USERNAME, JDBC_Config.PASSWORD);
		} catch (SQLException e) {
			System.out.println(e.getMessage());
		}
		
		// print to screen the names of all users once the server is starting
		printAllUsers();
	}

	public boolean addUser(String username, String email, String password) {
		boolean legal = chackSqlInjectionSafe(username, password);
		boolean legal2 = chackSqlInjectionSafe(email, "");
		boolean legal3 = !(username.equals(""));
		boolean legal4 = !(password.equals(""));
		if (!legal || !legal2 || !legal3 || !legal4) {
			return false;
		} else {
			if(!isAvailableUsername(username)) {
				ForumLogger.logGeneral(username + " is already in data");
				return false;
			}
			Member user = new Member(username,email);
			String sql = "INSERT INTO users VALUES ('" + username +"', '"+email+"', "+ user.getSalt()+",1,'" +((long)password.hashCode()+(long)user.getSalt())+"');";
			try {
				Statement s = this._sqlConnection.createStatement();
				s.executeUpdate(sql);
			} catch (SQLException e) {
				System.out.println("add user: "+e.getMessage());
				return false;
			}
			return true;
		}
	}

	public boolean authenticate(String username, String password) {
		boolean legal = chackSqlInjectionSafe(username, password);
		if (!legal) {
			return false;
		} else {
			String sql = "SELECT * FROM users WHERE username='" + username + "';";
			boolean found = false;
			try {
				Statement s = this._sqlConnection.createStatement();
				ResultSet r = s.executeQuery(sql);
				r.next();
				String name = r.getString("username");
				int salt = r.getInt("salt");
				long hashPassword =  Long.parseLong(r.getString("password"));
				if (name.equals(username) &&
						hashPassword == (long)password.hashCode()+salt){
					found = true; // known registered user!!
				}
				else{
					found = false;
				}
			} catch (SQLException e) {
				System.out.println("authenticate: "+e.getMessage());
				found = false;
			}
			return found;
		}
	}

	/**
	 * notice that type=1 means promote, type=-1 means demote
	 */
	public boolean changeRank(String username, int type) {
		boolean legal = chackSqlInjectionSafe(username, "");
		if (!legal) {
			return false;
		} else {
			String sql = "SELECT rank FROM users WHERE username='" + username + "';";
			boolean success = false;
			int oldRank = -10;
			try { // first find the rank to be replaced
				Statement s = this._sqlConnection.createStatement();
				ResultSet r = s.executeQuery(sql);
				r.next();
				oldRank = r.getInt("rank");
			} catch (SQLException e1) {
				return false;
			}
			if ( (type+oldRank < 1)  || (type+oldRank > 3) ){
				return false;
			}
			int newRank = oldRank + type;

			sql = "UPDATE users SET rank=" + newRank + " WHERE username='" + username + "';";
			try { // now update to newRank
				Statement s = this._sqlConnection.createStatement();
				if (s.executeUpdate(sql) > 0) {
					success = true;
				}
			} catch (SQLException e) {
				System.out.println("changeRank: "+e.getMessage());
				success = false;
			}
			return success;
		}
	}

	public boolean exists(String username) {
		return !this.isAvailableUsername(username);
	}

	public User getUser(String username) {
		boolean legal = chackSqlInjectionSafe(username, "");
		if (!legal) {
			return null;
		} else {
			Statement s = null;
			ResultSet res = null;
			boolean found = false;
			int rank = 1;
			int salt = 0;
			String email = "";
			String sql = "SELECT * FROM users WHERE username='" + username + "';";
			try {
				s = this._sqlConnection.createStatement();
				res = s.executeQuery(sql);
				found = res.next();
				if (found) {
					rank = res.getInt("rank");
					salt = res.getInt("salt");
					email = res.getString("email");
				}
			} catch (SQLException e) {
				System.out.println("get user: "+e.getMessage());
			}
			User user = new Member(username,email);
			user.setRank(rank);
			((Member)user).setSalt(salt);
			return user;
		}
	}

	public boolean removeUser(String username) {

		boolean legal = chackSqlInjectionSafe(username, "");
		if (!legal) {
			return false;
		} else {
			String sql = "DELETE FROM users WHERE username='" + username + "';";
			boolean success = false;
			try {
				Statement s = this._sqlConnection.createStatement();
				if (s.executeUpdate(sql) > 0) {
					success = true;
				}
			} catch (SQLException e) {
				System.out.println("remove user "+e.getMessage());
				success = false;
			}
			return success;
		}
	}


	public boolean updateUser(String username, String newEmail, String oldPass, String newPass) {
		boolean legal1 = authenticate(username, oldPass);
		boolean legal2 = chackSqlInjectionSafe(newPass, newEmail);
		if(!legal1 || !legal2 || newPass.length() < 3){
			return false;
		}else{
			String sql = "SELECT * FROM users WHERE username='" + username + "';";
			try {
				Statement s = this._sqlConnection.createStatement();
				ResultSet r = s.executeQuery(sql);
				r.next();
				int salt = r.getInt("salt");

				if(newEmail.length() > 0){
					sql = "UPDATE users SET email= '"+newEmail + "' WHERE username='" + username + "';";
					s = this._sqlConnection.createStatement();
					s.executeUpdate(sql);
				}
				sql = "UPDATE users SET password="+((long)newPass.hashCode()+(long)salt) + " WHERE username='" + username + "';";
				s = this._sqlConnection.createStatement();
				if (s.executeUpdate(sql) ==1) {
					ForumLogger.logUpdate(username);
					return true;	
				}
				//only one line in DB should have changed
				else if (s.executeUpdate(sql) > 1){
					System.out.println("WRONG!!!!!!!");
					return true;
				}
			} catch (SQLException e) {
				System.out.println("update User Pass: "+e.getMessage());
			}
			ForumLogger.logUpdateFail(username);
			return false;
		}
	}

	private boolean chackSqlInjectionSafe(String username, String password) {
		String illegal = "<>'\"=%$-!";
		for (int i = 0; i < illegal.length(); i++) {
			char c = illegal.charAt(i);
			if ((username.indexOf(c) != -1) || (password.indexOf(c) != -1)) {
				return false;
			}
		}
		return true;
	}

	private boolean isAvailableUsername(String username) {
		Statement s;
		try {
			s = this._sqlConnection.createStatement();
			String sql = "SELECT * FROM users WHERE username='" + username + "';";
			ResultSet r = s.executeQuery(sql);
			if (!r.next()){
				return true;
			}
			else{
				return false;
			}
		} catch (SQLException e) {
			System.out.println("is available: "+e.getMessage());
			return false;
		}

	}
	
	private void printAllUsers(){
		Statement s;
		try {
			s = this._sqlConnection.createStatement();
			String sql = "SELECT * FROM users;";
			ResultSet r = s.executeQuery(sql);
			r.next(); // skip admin
			System.out.println("************* All Users ******************");
			while(r.next()){
				System.out.println("("+r.getInt("rank")+") Name: "+r.getString("username")+"   Email: "+r.getString("email"));
			}
			System.out.println("*******************************************");
		} catch (SQLException e) {

		}
	}	
}
